package com.yanqu.road.utils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.regexp.RE;

/**
 * 随机工具类
 */
public class RandomHelper {
	
	private static Logger logger = LogManager.getLogger(RandomHelper.class.getName());

    private Random random = new Random();
	/**
	 * 字符集，排除o、O、0、1、I、l,字母大写
	 */
	final static char[] digits = {
			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
			'k', 'l','m', 'n','o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','A', 'B', 'C', 'D', 'E',
			'F', 'G', 'H', 'I', 'J', 'K', 'L','M', 'N','O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
	};

    public int next() {
        synchronized (this) {
            return random.nextInt();
        }
    }

    public int next(int maxValue) {
        synchronized (this) {
            return random.nextInt(maxValue);
        }
    }

    /**
     * 随机区间值，例如 a=1 b=10 随机，其结果值不包括10
     */
    public int next(int a, int b) {
        int minValue = Math.min(a, b);
        int maxValue = Math.max(a, b);
        synchronized (this) {
            if (minValue < maxValue) {
                return random.nextInt(maxValue - minValue) + minValue;
            }
        }
        return minValue;
    }

    public double nextDouble(double minValue, double maxValue) {
        synchronized (this) {
            if (minValue < maxValue) {
                return random.nextDouble() * (maxValue - minValue) + minValue;
            }
        }
        return minValue;
    }
    
    /**
     * 获取范围随机值
     *
     * @param range 如"100;200;10"
     * @return
     */
    public int next(String range) {
    	int value = 0;
    	int minValue = 0;
    	int maxValue = 0;
    	String[] strArray = range.split("\\;");
    	if (strArray.length >= 2) {
    		minValue = Integer.parseInt(strArray[0].trim());
        	maxValue = Integer.parseInt(strArray[1].trim());
        	value = next(minValue, maxValue);
        	if (strArray.length >= 3) {
        		// 取整值
        		int round = Integer.parseInt(strArray[2].trim());
        		value = (value / round) * round;
        	}
    	}
    	return value;
    }

	public String randomString(int i) {
		 StringBuffer sb=new StringBuffer(i);
         for(int j=0;j<i;j++){
			 int index = next(digits.length);
			 sb.append(digits[index]);
		 }
         return String.valueOf(sb);
	}


    /**
     * 随机容器内的一个值出来
     *
     * @param list
     * @param <T>
     * @return
     */
    public <T extends Collection> Object randomList(T list) {
        Object[] arrs = list.toArray();
        int index = next(arrs.length);
        return arrs[index];
    }


//    public static void main(String[] args) {
//        Map<Integer, Integer> map = new HashMap<>();
//        map.put(1, 1);
//        map.put(2, 2);
//        map.put(3555, 3);
//        map.put(344, 3);
//        map.put(32, 3);
//        map.put(31, 3);
//        map.put(22, 3);
//        map.put(5, 3);
//        Map<Integer, Integer> result = RandomHelper.randomMap(map, 3);
//        System.out.println(result);
//    }
    
    /**
     * 获取权重Key
     *
     * @param str 如"1;20|2;15|3;10"
     * @return
     */
    public static int getRandomKeyByWeight(String str) {
    	Random random = new Random();
    	int key = -1;
    	try {
    		List<Integer> keyList = new ArrayList<>();
    		List<Integer> weiList = new ArrayList<>();
	    	String[] keyWei = str.split("\\|");
	    	for (String kw : keyWei) {
	    		String[] s = kw.split(";");
	    		if (s.length >= 2) {
		    		keyList.add(Integer.parseInt(s[0].trim()));
		    		weiList.add(Integer.parseInt(s[1].trim()));
	    		}
	    	}
	    	int index = getRandomIndexByWeight(weiList, random);
	        return keyList.get(index);
    	} catch (Exception e) {
			logger.error("str=" + str, e);
			return key;
		}
    }

    /**
     * 获取权重Key。
     * @param str 如"1{fd1}20{fd2}2{fd1}15{fd2}3{fd1}10"
     * @param fh1
     * @param fh2
     * @return
     */
    public static int getRandomKeyByWeight(String str, String fh1, String fh2) {
        Random random = new Random();
        int key = -1;
        try {
            List<Integer> keyList = new ArrayList<>();
            List<Integer> weiList = new ArrayList<>();
            String[] keyWei = str.split(fh1);
            for (String kw : keyWei) {
                String[] s = kw.split(fh2);
                if (s.length >= 2) {
                    keyList.add(Integer.parseInt(s[0].trim()));
                    weiList.add(Integer.parseInt(s[1].trim()));
                }
            }
            int index = getRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("str=" + str, e);
            return key;
        }
    }

    /**
     * 获取权重Key
     *
     * @param wMap 如"{1=20, 2=20, 3=20}"
     * @return
     */
    public static int getRandomKeyByWeight(Map<Integer, Integer> wMap) {
        Random random = new Random();
        int key = -1;
        try {
            List<Integer> keyList = new ArrayList<>();
            List<Integer> weiList = new ArrayList<>();
            for (Entry<Integer, Integer> entry : wMap.entrySet()) {
                keyList.add(entry.getKey());
                weiList.add(entry.getValue());
            }
            int index = getRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("wMap=" + wMap, e);
            return key;
        }
    }

    /**
     * 获取权重Key,少创建点Random
     *
     * @param wMap 如"{1=20, 2=20, 3=20}"
     * @return
     */
    public int getRandomKeyByWeightEx(Map<Integer, Integer> wMap) {
        int key = -1;
        try {
            List<Integer> keyList = new ArrayList<>();
            List<Integer> weiList = new ArrayList<>();
            for (Entry<Integer, Integer> entry : wMap.entrySet()) {
                keyList.add(entry.getKey());
                weiList.add(entry.getValue());
            }
            int index = getRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("wMap=" + wMap, e);
            return key;
        }
    }

    /**
     * 获取权重Key
     *
     * @param wMap 如"{1=20, 2=20, 3=20}"
     * @return
     */
    public static long getRandomKeyByWeightForKeyLong(Map<Long, Integer> wMap) {
        Random random = new Random();
        int key = -1;
        try {
            List<Long> keyList = new ArrayList<>();
            List<Integer> weiList = new ArrayList<>();
            for (Entry<Long, Integer> entry : wMap.entrySet()) {
                keyList.add(entry.getKey());
                weiList.add(entry.getValue());
            }
            int index = getRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("wMap=" + wMap, e);
            return key;
        }
    }

    public static int getRandomKeyByLongWeight(Map<Integer, Long> wMap) {
        Random random = new Random();
        int key = -1;
        try {
            List<Integer> keyList = new ArrayList<>();
            List<Long> weiList = new ArrayList<>();
            for (Entry<Integer, Long> entry : wMap.entrySet()) {
                keyList.add(entry.getKey());
                weiList.add(entry.getValue());
            }
            int index = getLongListRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("wMap=" + wMap, e);
            return key;
        }
    }
    
    /**
     * 获取权重下标
     *
     * @param weightList
     * @return
     */
    public static int getRandomIndexByWeight(List<Integer> weightList) {
    	Random random = new Random();
    	return getRandomIndexByWeight(weightList, random);
    }

    /**
     * 获取权重下标
     *
     * @param weightList
     * @return
     */
    public static int getRandomIndexByWeight(List<Integer> weightList, Random random) {
        int allWeight = weightList.stream().mapToInt(intValue -> intValue.intValue()).sum();
        if (allWeight == 0){
            return -1;
        }
        int randomNum = random.nextInt(allWeight) + 1;
        int nowWeight = 0;
        for (int index = 0; index < weightList.size(); index++) {
            nowWeight += weightList.get(index);
            if (nowWeight >= randomNum) {
                return index;
            }
        }
        return -1;
    }

    /**
     * 获取权重下标
     */
    public static int getLongListRandomIndexByWeight(List<Long> weightList, Random random) {
        long allWeight = weightList.stream().mapToLong(longValue -> longValue).sum();
        long randomNum = BigDecimal.valueOf(allWeight).multiply(BigDecimal.valueOf(random.nextDouble())).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        long nowWeight = 0;
        for (int index = 0; index < weightList.size(); index++) {
            nowWeight += weightList.get(index);
            if (nowWeight >= randomNum) {
                return index;
            }
        }
        return -1;
    }

    /**
     * 取随机不重复的数
     *
     * @param max
     * @param num
     * @return
     */
    public static List<Integer> getDifferentRandomNum(int max, int num) {
        List<Integer> numList = new ArrayList<>();
        Random random = new Random();
        if (max - 0 >= num) {
            for(int i = 0; i < 10000; i++) {
                if (numList.size() >= num) {
                    break;
                }

                int index = random.nextInt(max);
                if (numList.contains(index)) {
                    continue;
                } else {
                    numList.add(index);
                }
            }
        }
        return numList;
    }

    /**
     * Returns a pseudorandom, uniformly distributed value
     * between 0 (inclusive) and the specified value (exclusive).
     *
     * @param n the bound on the random number to be returned.  Must be
     *        positive.
     * @return the next value
     * @throws IllegalArgumentException if n is not positive
     */
    public static long nextLong(long n) {
        if (n <= 0) {
            throw new IllegalArgumentException("n must be positive");
        }

        long offset = 0;
        Random random = new Random();
        while (n >= Integer.MAX_VALUE) {
            int bits = random.nextInt(2);
            long half = n >>> 1;
            long nextn = ((bits & 2) == 0) ? half : n - half;
            if ((bits & 1) == 0) {
                offset += n - nextn;
            }
            n = nextn;
        }
        return offset + random.nextInt((int) n);
    }

    /**
     * 打乱List
     */
    public void shuffleList(List<?> list) {
        synchronized (this) {
            Collections.shuffle(list, random);
        }
    }

    /**
     * 获取权重下标
     */
    public int getSafeRandomIndexByWeight(List<Integer> weightList) {
        int allWeight = weightList.stream().mapToInt(intValue -> intValue.intValue()).sum();
        int randomNum;
        synchronized (this) {
            randomNum = random.nextInt(allWeight) + 1;
        }
        int nowWeight = 0;
        for (int index = 0; index < weightList.size(); index++) {
            nowWeight += weightList.get(index);
            if (nowWeight >= randomNum) {
                return index;
            }
        }
        return -1;
    }

    /**
     * 在指定范围[begin,end]内取得takeNum个随机整数,最多遍历次数end-begin
     * @param begin 起始值,begin>=0
     * @param end 结束值,end>=begin,end<=1000000000
     * @param takeNum 取的数量,大于范围时全取出
     */
    public List<Integer> getRandomDistinctInteger(int begin, int end, int takeNum) {
        List<Integer> takeList = new ArrayList<>();
        if (begin > end || begin < 0 || takeNum <= 0) {
            return takeList;
        }
        if (begin == end) {
            takeList.add(begin);
        } else {
            int range = end - begin + 1;
            int randomNum = random.nextInt(1000000000) + 1000000000;
            for (int i = 0; i < range && takeNum > 0; i++) {
                if (randomNum % (range - i) < takeNum) {
                    takeList.add(i + begin);
                    takeNum--;
                }
            }
        }

        return takeList;
    }

    /**
     * map随机获取元素
     * @param map
     * @param n 随机选择的元素数量
     * @return
     */
    public static <T> Map<Integer, T> randomMap(Map<Integer, T> map, int n) {
        if (map.size() <= n) {
            return map;
        }
        Map<Integer, T> result = new HashMap<>();
        for (int i = 0; i < n; i++) {
            Integer randomKey = RandomHelper.getRandomElement(map.keySet());
            if (randomKey == null) {
                break;
            }
            T randomValue = map.get(randomKey);
            result.put(randomKey, randomValue);
            // 删除已经选取过的元素
            map.remove(randomKey);
        }
        return result;
    }

    public static <T> T getRandomElement(Set<T> set) {
        int size = set.size();
        if (size == 0) {
            return null;
        }
        int itemIndex = new Random().nextInt(size); // 随机生成索引
        int currentIndex = 0;
        for (T element : set) {
            if (currentIndex == itemIndex) {
                return element;
            }
            currentIndex++;
        }
        return null; // 如果集合为空，则返回null
    }

    /**
     * 从给定的Set中随机选择n个元素并返回一个新的Set。
     *
     * @param originalSet 原始Set
     * @param n 要选择的元素数量
     * @param <T> Set中的元素类型
     * @return 包含随机选择元素的新Set
     */
    public static <T> Set<T> selectRandomElements(Set<T> originalSet, int n) {
        if (originalSet == null || n <= 0) {
            return originalSet;
        }
        List<T> list = new ArrayList<>(originalSet);
        Collections.shuffle(list, new Random());
        if (n > list.size()) {
            n = list.size(); // 如果n大于集合大小，调整为集合的实际大小
        }
        return new HashSet<>(list.subList(0, n));
    }

    /**
     * 从list中随机出一个元素，且元素不在set中
     *
     */
    public <T> T getRandomElementExcludingSet(List<T> list, Set<T> excludingSet) {
        if (list.isEmpty()) {
            throw new IllegalArgumentException("List is empty.");
        }

        List<T> tempList = new ArrayList<>(list);
        tempList.removeAll(excludingSet);

        if (tempList.isEmpty()) {
            throw new IllegalArgumentException("No elements in the list are outside the set.");
        }

        int randomIndex = random.nextInt(tempList.size());
        return tempList.get(randomIndex);
    }

    /**
     * 随机出list中的n个
     * @param numbers
     * @param n
     * @return
     */
    public static <T> List<T> getRandomList(List<T> numbers, int n) {
        List<T> list = new ArrayList<>(numbers);
        Collections.shuffle(list);

        List<T> resultList = new ArrayList<>();
        for (int i = 0; i < n && i < list.size(); i++) {
            resultList.add(list.get(i));
        }
        return resultList;
    }

    /**
     * 从给定的列表中随机选择一个元素。
     *
     * @param <T> 列表中元素的类型
     * @param list 要从中随机选择元素的列表
     * @return 随机选择的元素
     */
    public static <T> T getRandomElement(List<T> list) {
        Random random = new Random();
        int index = random.nextInt(list.size());
        return list.get(index);
    }

    /**
     * 从给定的列表中随机选择一个元素,并移除
     *
     * @param <T> 列表中元素的类型
     * @param list 要从中随机选择元素的列表
     * @return 随机选择的元素
     */
    public static <T> T getRandomElementAndRemove(List<T> list) {
        Random random = new Random();
        int index = random.nextInt(list.size());
        return list.remove(index);
    }

    /**
     * 将sum随机分成n份，每份至少为min
     * 最大随机范围在0~剩余值的1/maxPart
     */
    public List<BigInteger> randomSplitAbility(BigInteger sum, BigInteger min, int maxPart, int n) {
        List<BigInteger> parts = new ArrayList<>(n);
        BigInteger remaining = sum.subtract(min.multiply(BigInteger.valueOf(n))); // 预先扣除保底总和

        if (remaining.compareTo(BigInteger.ZERO) < 0) {
            throw new IllegalArgumentException("总数不满足保底");
        }

        for (int i = 0; i < n - 1; i++) {
            // 计算随机部分的最大值，不超过剩余值的1/maxPart
            BigInteger maxRandomPart = remaining.divide(BigInteger.valueOf(maxPart));
            // 随机生成一个0到maxRandomPart的数值
            BigInteger randomPart = (maxRandomPart.compareTo(BigInteger.ZERO) > 0)
                    ? new BigInteger(maxRandomPart.bitLength(), random).mod(maxRandomPart)
                    : BigInteger.ZERO;
            // 计算最终的部分大小，包含随机部分和保底值
            BigInteger part = randomPart.add(min);
            // 添加到列表
            parts.add(part);
            // 更新剩余
            remaining = remaining.subtract(randomPart);
        }

        // 添加最后一份，包括所有剩余和保底值
        parts.add(remaining.add(min));

        // 排序确保列表按降序排列
        parts.sort(Collections.reverseOrder());
        return parts;
    }

    public static void main(String[] args) {

    }

    public static int rand1000() {
        Random random = new Random();
        return random.nextInt(1000);
    }

    /**
     * 千分比概率是否命中
     * @param useRate
     * @return
     */
    public static boolean randRate(int useRate) {
        int realRand = rand1000();
        if (realRand < useRate) {
            return true;
        }
        return false;
    }

    /**
     * 获取权重Key
     *
     * @param wMap 如"{"1;110111=1"=20, "1;110111=2"=20, "1;110111=3"=20}"
     * @return String
     */
    public String getRandomStrKeyByWeightEx(Map<String, Integer> wMap) {
        try {
            List<String> keyList = new ArrayList<>();
            List<Integer> weiList = new ArrayList<>();
            for (Entry<String, Integer> entry : wMap.entrySet()) {
                keyList.add(entry.getKey());
                weiList.add(entry.getValue());
            }
            int index = getRandomIndexByWeight(weiList, random);
            return keyList.get(index);
        } catch (Exception e) {
            logger.error("wMap=" + wMap, e);
            return null;
        }
    }
}
